package com.sweet.serializer;

import com.sweet.enums.SerializerTypeEnum;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import lombok.Data;

/**
 * ProtoStuff序列化
 * JDK1.6及以上都支持
 * 注意：ProtoStuff对数组、集合类元素不支持，仅对基础类型支持，因此统一采用自定义包装类封装执行
 *
 * @author limi
 * @date 2020-07-28 16:29
 */
public class PstSerializer implements ISerializer {
    /**
     * 定义包装类Schema
     */
    private static final Schema<ObjectWrapper> SCHEMA = RuntimeSchema.getSchema(ObjectWrapper.class);

    @Override
    public SerializerTypeEnum type() {
        return SerializerTypeEnum.PROTO_STUFF;
    }

    @Override
    public byte[] serialize(Object obj) throws Exception {
        if (obj == null) {
            return null;
        }

        //原始版本:(未采用自定义包装类，不支持集合、数组等)
        //基于缓存延迟创建，采用了ConcurrentHashMap线程安全缓存
        //Schema schema = RuntimeSchema.getSchema(obj.getClass());
        //Re-use (manage) this buffer to avoid allocating on every serialization
        //LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
        //序列化
        //try {
        //    return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
        //} finally {
        //    buffer.clear();
        //}

        // Re-use (manage) this buffer to avoid allocating on every serialization
        LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);

        // 序列化
        try {
            return ProtostuffIOUtil.toByteArray(new ObjectWrapper(obj), SCHEMA, buffer);
        } finally {
            buffer.clear();
        }
    }

    @Override
    public <T> T deserialize(byte[] bytes, Class<T> cls) throws Exception {
        if (bytes == null || bytes.length == 0) {
            return null;
        }

        //原始版本:(未采用自定义包装类，不支持集合、数组等)
        //基于缓存延迟创建，采用了ConcurrentHashMap线程安全缓存
        //Schema<T> schema = RuntimeSchema.getSchema(cls);
        //反序列化
        //T obj = schema.newMessage();
        //ProtostuffIOUtil.mergeFrom(bytes, obj, schema);
        //return obj;

        // 反序列化
        ObjectWrapper<T> obj = SCHEMA.newMessage();
        ProtostuffIOUtil.mergeFrom(bytes, obj, SCHEMA);
        return obj.getObject();
    }

    /**
     * 定义临时包装类，封装序列化数据，便于Protostuff成功执行
     */
    @Data
    private static class ObjectWrapper<T> {
        private T object;

        public ObjectWrapper(T object) {
            this.object = object;
        }
    }
}